import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Not, Repository } from 'typeorm';
import { Menu } from './entities/menu.entity';
import { CreateMenuDto } from './dto/create-menu.dto';
import { UpdateMenuDto } from './dto/update-menu.dto';

@Injectable()
export class MenuService {
  @InjectRepository(Menu)
  private menuRepository: Repository<Menu>;

  async create(createMenuDto: CreateMenuDto) {
    const { name, path, order, parentId } = createMenuDto;

    const existMenu = await this.menuRepository.findOne({ where: { name } });

    if (existMenu) {
      throw new HttpException('菜单已存在', HttpStatus.BAD_REQUEST);
    }

    const menu = new Menu();
    menu.name = name;
    menu.path = path;
    menu.order = order;

    if (parentId) {
      const parent = await this.menuRepository.findOne({
        where: { id: parentId },
      });
      if (!parent) {
        throw new HttpException('父级菜单不存在', HttpStatus.BAD_REQUEST);
      }
      menu.parent = parent;
    }

    try {
      await this.menuRepository.save(menu);
      return '创建成功';
    } catch (e) {
      throw new HttpException('创建失败', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  async findTree() {
    const allMenus = await this.menuRepository.find({
      relations: ['children'],
      order: {
        order: 'ASC',
      },
    });

    const rootMenus = allMenus.filter((menu) => !menu.parent);

    const buildTree = (menus: Menu[]) => {
      return menus.map((menu) => {
        const node = {
          id: menu.id,
          name: menu.name,
          path: menu.path,
          order: menu.order,
          children: [],
        };

        if (menu.children && menu.children.length > 0) {
          node.children = buildTree(menu.children);
        }

        return node;
      });
    };

    return buildTree(rootMenus);
  }

  async findOne(id: number) {
    const menu = await this.menuRepository.findOne({
      where: { id },
      relations: ['parent', 'children'],
    });

    if (!menu) {
      throw new HttpException('菜单不存在', HttpStatus.BAD_REQUEST);
    }

    return menu;
  }

  async update(id: number, updateMenuDto: UpdateMenuDto) {
    const { name, path, order, parentId } = updateMenuDto;

    const menu = await this.menuRepository.findOne({
      where: { id },
      relations: ['parent'],
    });

    if (!menu) {
      throw new HttpException('菜单不存在', HttpStatus.BAD_REQUEST);
    }

    if (name) {
      const existMenu = await this.menuRepository.findOne({
        where: { name, id: Not(id) },
      });

      if (existMenu) {
        throw new HttpException('菜单名已存在', HttpStatus.BAD_REQUEST);
      }

      menu.name = name;
    }

    if (path) {
      menu.path = path;
    }

    if (order) {
      menu.order = order;
    }

    if (parentId !== undefined) {
      if (parentId === null) {
        menu.parent = null;
      } else {
        const parent = await this.menuRepository.findOne({
          where: { id: parentId },
        });
        if (!parent) {
          throw new HttpException('父级菜单不存在', HttpStatus.BAD_REQUEST);
        }
        if (parent.id === menu.id) {
          throw new HttpException(
            '不能将自己设为父级菜单',
            HttpStatus.BAD_REQUEST,
          );
        }
        menu.parent = parent;
      }
    }

    try {
      await this.menuRepository.save(menu);
      return '更新成功';
    } catch (e) {
      throw new HttpException('更新失败', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }

  async remove(id: number) {
    const menu = await this.menuRepository.findOne({
      where: { id },
      relations: ['children'],
    });

    if (!menu) {
      throw new HttpException('菜单不存在', HttpStatus.BAD_REQUEST);
    }

    if (menu.children && menu.children.length > 0) {
      throw new HttpException('请先删除子菜单', HttpStatus.BAD_REQUEST);
    }

    try {
      await this.menuRepository.remove(menu);
      return '删除成功';
    } catch (e) {
      throw new HttpException('删除失败', HttpStatus.INTERNAL_SERVER_ERROR);
    }
  }
}
